from pydantic import BaseModel, field_serializer, Field
from typing import Optional, List, Any
from src.settings import setting
from datetime import datetime


class LoginRequest(BaseModel):
    username: str
    password: str


class RoleSchema(BaseModel):
    id: int
    name: str

    class Config:
        from_attributes = True


class UserSchema(BaseModel):
    id: int
    username: str
    nick_name: str
    avatar: str
    email: str
    is_active: bool
    gender: str
    phone: str
    roles_detail: Any | None = []
    roles: Any | None = []
    dept_id: int | None = []
    job: Any | None = []

    class Config:
        from_attributes = True

    # @classmethod
    # def from_orm(cls, obj):
    #     data = super().from_orm(obj)
    #     data.avatar = f"http://{setting.APP_HOST}:{setting.APP_PORT}/media/{data.avatar}"
    #     return data
    @classmethod
    async def from_common_orm(cls, obj):
        obj_dict = cls.from_orm(obj).dict()
        obj_dict['avatar'] = f"http://{setting.APP_HOST}:{setting.APP_PORT}/media/{obj_dict['avatar']}"
        roles = await obj.roles.all()
        obj_dict['roles_detail'] = [{'id': role.id, 'name': role.id} for role in roles]
        obj_dict['roles'] = [role.id for role in roles]
        obj_dict['roles_name'] = [role.name for role in roles]
        obj_dict['dept_id'] = obj.dept_id
        obj_dict['job'] = [job.id for job in await obj.job.all()]
        return obj_dict


class UserInSchema(BaseModel):
    username: str
    nick_name: str
    gender: int
    email: str
    phone: int
    is_active: bool
    roles: List[int] | None = []
    dept_id: int | None = None
    job: List[int] | None = []


class MenuPermissionSchema(BaseModel):
    name: str
    title: str
    icon: str | None
    path: str | None
    component: str | None
    children: Any | None

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj, menus_ids=None):
        obj_dict = cls.from_orm(obj).dict()
        if menus_ids:
            children = await obj.children.filter(type=1, id__in=menus_ids).all()
        else:
            children = await obj.children.filter(type=1).all()
        obj_dict["children"] = [await cls.from_orm_recursive(child) for child in children]
        return obj_dict


class DeptOutSchema(BaseModel):
    pid_id: int | None = Field(default=None, validation_alias='pid_id')
    id: int
    name: str
    enabled: bool
    dept_sort: int
    create_time: datetime
    # children: List['DeptOutSchema'] | None = []
    children: Any | None

    class Config:
        from_attributes = True

    @field_serializer('create_time')
    def serialize_create_time(self, value: datetime | None, _info):
        if value is None:
            return None
        return value.isoformat()

    @classmethod
    async def from_orm_recursive(cls, obj):
        dept_dict = cls.from_orm(obj).dict()
        children = await obj.children.filter(is_delete=False).all()
        dept_dict['children'] = [await cls.from_orm_recursive(child) for child in children]
        return dept_dict


class DeptOutTreeSchema(BaseModel):
    value: int = Field(alias='id')
    label: str = Field(alias='name')
    children: Any | None = []

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj):
        obj_dict = cls.from_orm(obj).dict()
        children = await obj.children.all()
        obj_dict['children'] = [await cls.from_orm_recursive(child) for child in children]
        return obj_dict


class DeptInSchema(BaseModel):
    pid_id: int | None = None
    name: str
    enabled: bool
    sub_count: int | None = None
    dept_sort: int

    class Config:
        from_attributes = True


# 岗位相关
class JobOutSchema(BaseModel):
    pid_id: int | None = None
    id: int
    name: str
    enabled: bool
    job_sort: int
    children: Any | None

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj):
        job_dict = cls.from_orm(obj).dict()
        children = await obj.children.filter(is_delete=False).all()
        job_dict['children'] = [await cls.from_orm_recursive(child) for child in children]
        return job_dict


class JobInSchema(BaseModel):
    name: str
    enabled: bool
    job_sort: int

    class Config:
        from_attributes = True


class RoleOutSchema(BaseModel):
    id: int
    name: str
    level: int
    description: str
    data_scope: str
    status: bool
    menus: Any | None = []

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj):
        obj_dict = cls.from_orm(obj).dict()
        menus = await obj.menus.all()
        obj_dict['menus'] = [menu.id for menu in menus]
        return obj_dict


class RoleInSchema(BaseModel):
    name: str
    level: int
    description: str
    data_scope: str
    status: bool
    menus: list[int] | None = []

    class Config:
        from_attributes = True


class MenuInSchema(BaseModel):
    pid_id: int | None = None
    sub_count: int | None = None
    # 0 菜单，1 子菜单，2 按钮
    type: int | None = None
    title: str | None = None
    name: str
    component: str | None = None
    menu_sort: int | None = None
    icon: str | None = None
    path: str | None = None
    i_frame: bool | None = None
    cache: bool | None = None
    hidden: bool | None = None
    permission: str | None = None
    is_menu: bool | None = None

    class Config:
        from_attributes = True


class MenuOutSchema(BaseModel):
    pid_id: int | None = None
    id: int
    sub_count: int | None = None
    # 0 菜单，1 子菜单，2 按钮
    type: int | None = None
    title: str | None = None
    name: str
    component: str | None = None
    menu_sort: int | None = None
    icon: str | None = None
    path: str | None = None
    i_frame: bool | None = None
    cache: bool | None = None
    hidden: bool | None = None
    permission: str | None = None
    is_menu: bool | None = None
    children: Any | None = []

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj):
        obj_dict = cls.from_orm(obj).dict()
        children = await obj.children.filter(is_delete=False).all()
        obj_dict['children'] = [await cls.from_orm_recursive(child) for child in children]
        return obj_dict


class MenuOutTreeSchema(BaseModel):
    value: int = Field(alias='id')
    label: str = Field(alias='title')
    children: Any | None = []

    class Config:
        from_attributes = True

    @classmethod
    async def from_orm_recursive(cls, obj):
        obj_dict = cls.from_orm(obj).dict()
        children = await obj.children.filter(is_delete=False).all()
        obj_dict['children'] = [await cls.from_orm_recursive(child) for child in children]
        return obj_dict
